#include "socket_runner.h"

#include <arpa/inet.h>
#include <poll.h>
#include <sys/socket.h>
#include <unistd.h>
#include <memory>
#include <vector>

#include "logger.h"
#include "socket_client.h"
#include "socket_data.h"

SocketRunner::SocketRunner(int socketFd)
    : socketFd_(socketFd)
{
}

void SocketRunner::Run()
{
    while (true) {
        std::vector<struct pollfd> pfds = {
            { .fd = socketFd_, .events = POLLIN, },
        };
        for (auto &[fd, _] : clients_) {
            pfds.push_back({.fd = fd, .events = POLLIN});
        }

        if (poll(pfds.data(), pfds.size(), -1) < 0) {
            LOGGER() << "poll failed\n";
            break;
        }

        if (pfds[0].revents & POLLIN) {
            struct sockaddr_in clientAddr;
            socklen_t addrlen = sizeof(sockaddr);
            int clientFd = accept(socketFd_,
                                  reinterpret_cast<struct sockaddr *>(
                                      &clientAddr),
                                  &addrlen);
            auto client = std::make_shared<SocketClient>(clientFd);
            clients_[clientFd] = std::move(client);
            LOGGER()
                << "client connected: "
                << clientAddr.sin_addr.s_addr
                << ", port: " << clientAddr.sin_port
                << std::endl;
            continue;
        }

        for (auto &pfd : pfds) {
            if (!(pfd.revents & POLLIN)) {
                continue;
            }

            struct SocketData data = {};
            auto size = read(pfd.fd, &data, sizeof(data));

            auto it = clients_.find(pfd.fd);
            if (it == clients_.end()) {
                continue;
            }

            auto &client = it->second;
            if (size == 0) {
                LOGGER() << "client disconnect\n";
                clients_.erase(it);
            } else if (size > 0) {
                client->RunTask(data.message);
            }
        }
    }
}

void SocketRunner::Stop()
{
}
